home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
oper_sys
/
choices
/
chcssml1.lha
/
Clock.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-02-06
|
4KB
|
173 lines
/*
* This file is part of the Choices Operating System Simulator
* Developed by: The TAPESTRY Parallel Computing Laboratory
* University of Illinois at Urbana-Champaign
* Department of Computer Science
* 1304 W. Springfield Ave.
* Urbana, IL 61801
*
* Copyright (c) 1987, 1988, 1989 The University of Illinois Board of Trustees.
* All Rights Reserved.
* CONFIDENTIAL INFORMATION. Distribution restricted under license agreement.
*
* Author: Gary M. Johnston (johnston@cs.uiuc.edu)
* Project Manager and Principal Investigator: Roy Campbell (roy@cs.uiuc.edu)
*
* Funded by: NSF TAPESTRY Grant No. 1-5-30035, NASA ICLASS Grant
* No. 1-5-25469 and No. NSG1471 and AT&T Metronet Grant No. 1-5-37411.
*/
/*
* Clock.c - Microtimeslicing.
*
* $Header: Clock.c,v 1.4 88/02/16 10:59:31 johnston Exp $
* $Locker: johnston $
*/
#include "Assert.h"
#include "Debug.h"
#include "Clock.h"
#include "Print.h"
#include "Process.h"
#include "Signal.h"
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <task.h>
extern int setitimer( int, itimerval *, itimerval * );
extern int sigsetmask( int );
const int Timer = ITIMER_VIRTUAL; // Virtual process time timer.
const int Signal = SIGVTALRM; // Signal sent upon timer expiration.
const int Mask = sigmask(Signal); // Signal as a mask.
const int Interval = 10000; // Microtimeslicing interval.
static inline int
Blocked( int mask )
{
/*
* Return non-zero iff the signals in mask are currently blocked.
*/
return (sigblock(0) & mask);
}
int
IsAProcessTask( task * t )
{
/*
* Return non-zero iff the task is a ProcessTask.
*
* WARNING: This method of figuring out whether or not a task is
* a ProcessTask is disgusting.
*/
if ( t == 0 )
return(0);
const char * const name = "ProcessTask";
const int length = 11;
return ( strncmp( t->t_name, name, length ) == 0 );
}
static void
ClockHandler( int sig, int code, Sigcontext * scp )
{
/*
* UNIX signal handler.
* The basic job is to microtimeslice preemptable ProcessTasks.
*/
Assert(sig == Signal);
Assert(code == 0);
Assert(scp != 0);
/*
* Unblock the Signal.
* It's automatically blocked when the Signal is delivered.
* We have to do this before we might delay, because
* the delay would relinquish.
*/
Assert(Blocked(Mask));
sigsetmask(0);
/*
* If the current task is a ProcessTask and is preemptable,
* then delay it (i.e., microtimeslice ended).
* Otherwise, let it continue.
*/
if ( IsAProcessTask( thistask ) ) {
ProcessTask * p = (ProcessTask *) thistask;
if ( p->setPreemptable( 0 ) ) {
Debug("ClockHandler: %s delay.\n", p->t_name);
//Print(".");
p->delay(1);
p->setPreemptable(1);
Assert(!Blocked(Mask));
return;
}
Debug("ClockHandler: %s no delay.\n", p->t_name);
Assert(!Blocked(Mask));
return;
}
Debug("ClockHandler: %s continue.\n", thistask->t_name);
Assert(!Blocked(Mask));
}
void
StartClock()
{
/*
* Arrange for ClockHandler() to catch the Timer Signals
* and then start the Timer. The Timer is set to automatically
* reset itself, so we don't have to restart it each time it expires.
* This makes ClockHandler simpler and quicker.
*/
/*
* Aim Signal at ClockHandler.
*/
Sigvec vec;
vec.sv_handler = ClockHandler;
vec.sv_mask = 0;
vec.sv_onstack = 0;
if ( sigvec( Signal, &vec, (Sigvec *) 0 ) != 0 ) {
perror("StartClock: sigvec");
exit(1);
}
/*
* Start the Timer.
*/
itimerval value;
const int sec = Interval / 1000000;
const int usec = Interval % 1000000;
value.it_interval.tv_sec = sec;
value.it_interval.tv_usec = usec;
value.it_value.tv_sec = sec;
value.it_value.tv_usec = usec;
if ( setitimer( Timer, &value, (itimerval *) 0 ) != 0 ) {
perror("StartClock: setitimer");
exit(1);
}
Assert(!Blocked(Mask));
}
int
BlockClock()
{
/*
* Block Timer Signals.
* Return previous mask.
*/
Assert(sigblock(0) == 0);
return (sigblock(Mask));
}
void
UnblockClock( int mask )
{
/*
* Restore previous mask.
*/
Assert(mask == 0);
sigsetmask(mask);
}